#include "maxq_config.h"
#include "i2c\maxq_i2c.h"

/***** Definitions *****/

#ifdef __IAR_SYSTEMS_ICC__

#define SCL_PD   PD1_bit.bit4
#define SCL_PI   PI1_bit.bit4
#define SCL_PO   PO1_bit.bit4
#define SDA_PD   PD1_bit.bit5
#define SDA_PI   PI1_bit.bit5
#define SDA_PO   PO1_bit.bit5

#define SCL_LO() SCL_PD = 1
#define SCL_HI()  SCL_PD = 0
#define SDA_LO() SDA_PD = 1
#define SDA_HI()  SDA_PD = 0

#else

#define SCL_PD    PD1
#define SCL_PI    PI1
#define SCL_PO    PO1
#define SCL_MASK  0x10
#define SDA_PD    PD1
#define SDA_PI    PI1
#define SDA_PO    PO1
#define SDA_MASK  0x20

#define SCL_LO()  SCL_PD |= SCL_MASK
#define SCL_HI()  SCL_PD &= ~SCL_MASK
#define SDA_LO()  SDA_PD |= SCL_MASK
#define SDA_HI()  SDA_PD &= ~SCL_MASK

#endif


#define DELAY_VALUE 0x07

#if 0
#define HALF_CLK() \
  __asm("nop"); __asm("nop"); __asm("nop"); __asm("nop"); \
  __asm("nop"); __asm("nop"); __asm("nop"); __asm("nop"); \
  __asm("nop"); __asm("nop"); __asm("nop"); __asm("nop");
#else
#define HALF_CLK() \
  delay++; delay++; delay++; delay++;
#endif

/***** Function Prototypes *****/


/***** Global Data *****/

/***** File Scope Data *****/
static volatile unsigned int delay;
static int ack;

/****************************************************************************/
int i2c_master_init(i2c_speed_t i2cspeed)
{
  SCL_PD = 0; // set as input
  SCL_PO = 0; // disable pull-up
  SDA_PD = 0; // set as input
  SDA_PO = 0; // disable pull-up

  return MAXQ_SUCCESS;
}

/****************************************************************************/
int i2c_master_send_byte(uint8_t data)
{
  int i;

  SCL_LO();
  ack = 0;

  for (i = 9; i > 0; i--) {
    if ( (i > 1) && !(data & 0x80) )
      SDA_LO();
    else
      SDA_HI();
  
    HALF_CLK();
    SCL_HI();
    while(!SCL_PI);

    if (i > 1)
      data <<= 1;
    else
      ack = !SDA_PI;
  
    HALF_CLK();
    SCL_LO();
  }

  if (!ack)
    return MAXQ_FAILURE;

  return MAXQ_SUCCESS;
}

/****************************************************************************/
int i2c_master_get_byte(uint8_t * data)
{
  int i;
  uint8_t temp = 0;

  SCL_LO();

  for (i = 9; i > 0; i--) {
    if ( (i == 1) && ack )
      SDA_LO();
    else
      SDA_HI();
  
    HALF_CLK();
    SCL_HI();
    while(!SCL_PI);

    if (i > 1) {
      temp <<= 1;
      temp |= SDA_PI;
    }
  
    HALF_CLK();
    SCL_LO();
  }

  *data = temp;

  return MAXQ_SUCCESS;
}

/****************************************************************************/
int i2c_master_read(uint16_t address, int length, uint8_t *data)
{
  // Prepare to ACK receptions
  ack = 1;

  if (i2c_master_start() != MAXQ_SUCCESS)
    return MAXQ_FAILURE;

  if (i2c_master_send_byte((address << 1) | 1) != MAXQ_SUCCESS) {
    i2c_master_stop();
    return MAXQ_FAILURE;
  }

  for (; length > 0; length--) {

    // If this is the last byte, NACK
    if (length == 1) {
      ack = 0;
    }

    if (!i2c_master_get_byte(data++)) {
      i2c_master_stop();
      return MAXQ_FAILURE;
    }
  }

  return i2c_master_stop();
}

/****************************************************************************/
int i2c_master_write(uint16_t address, int length, uint8_t * data)
{
  if(i2c_master_start() != MAXQ_SUCCESS)
    return MAXQ_FAILURE;

  if (i2c_master_send_byte(address << 1) != MAXQ_SUCCESS) {
    i2c_master_stop();
    return MAXQ_FAILURE;
  }

  while (length-- > 0) {
    if (i2c_master_send_byte(*data++) != MAXQ_SUCCESS) {
      i2c_master_stop();
      return MAXQ_FAILURE;
    }
  }

  return i2c_master_stop();
}

/****************************************************************************/
int i2c_master_start(void)
{
  SCL_HI();
  while(!SCL_PI);
  SDA_LO();
  HALF_CLK();

  return MAXQ_SUCCESS;
}

/****************************************************************************/
int i2c_master_stop(void)
{
  SCL_LO();
  HALF_CLK();
  SDA_LO();
  HALF_CLK();
  SCL_HI();
  while(!SCL_PI);
  HALF_CLK();
  SDA_HI();

  return MAXQ_SUCCESS;
}
